// client.cpp
#include "client.hpp"
#include "exclusive_unix_listener.hpp"
#include <sys/epoll.h>
#include <unordered_map>
#include <vector>
#include <thread>
#include <atomic>
#include <iostream>
#include <stdexcept>

namespace uds_model {
class Client::Impl {
public:
    explicit Impl(const std::string& path) 
        : path_(path), sock_(-1), connected_(false) {}
    
    ~Impl() { disconnect(false); }

    void connect() {
        if (connected_) return;
        
        try {
            auto s = uds::connect(path_);
            sock_ = ::dup(s.native());
            if (sock_ == -1) {
                throw std::system_error(errno, std::system_category(), "dup");
            }
            
            // 设置非阻塞模式（可选）
            int flags = fcntl(sock_, F_GETFL, 0);
            fcntl(sock_, F_SETFL, flags | O_NONBLOCK);
            
            connected_ = true;
            inbuf_.clear(); // 清除之前的缓冲区
        } catch (...) {
            if (sock_ != -1) {
                ::close(sock_);
                sock_ = -1;
            }
            connected_ = false;
            throw;
        }
    }
    
    void disconnect(bool throw_on_error = true) {
        if (!connected_) return;
        
        if (sock_ != -1) {
            if (::close(sock_) == -1 && throw_on_error) {
                throw std::system_error(errno, std::system_category(), "close");
            }
            sock_ = -1;
        }
        connected_ = false;
        inbuf_.clear();
    }

    void send_line(const std::string& line) {
        if (!connected_) throw std::logic_error("Connection not established");
        
        std::string out = line + '\n';
        ssize_t sent = 0;
        while (sent < static_cast<ssize_t>(out.size())) {
            ssize_t n = ::send(sock_, out.data() + sent, out.size() - sent, MSG_NOSIGNAL);
            if (n == -1) {
                if (errno == EAGAIN || errno == EWOULDBLOCK) continue;
                disconnect();
                throw std::system_error(errno, std::system_category(), "send");
            }
            sent += n;
        }
    }

    std::string read_line() {
        if (!connected_) throw std::logic_error("Connection not established");
        
        while (true) {
            std::size_t pos = inbuf_.find('\n');
            if (pos != std::string::npos) {
                std::string ret = inbuf_.substr(0, pos);
                inbuf_.erase(0, pos + 1);
                return ret;
            }
            
            char buf[1024];
            ssize_t n = recv(sock_, buf, sizeof(buf), 0);
            if (n == 0) {
                disconnect();
                throw std::runtime_error("Peer closed connection");
            }
            if (n == -1) {
                if (errno == EAGAIN || errno == EWOULDBLOCK) {
                    // 使用select/poll等待可读状态
                    fd_set rfds;
                    FD_ZERO(&rfds);
                    FD_SET(sock_, &rfds);
                    timeval tv{.tv_sec = 3, .tv_usec = 0}; // 3秒超时
                    
                    int res = select(sock_ + 1, &rfds, nullptr, nullptr, &tv);
                    if (res == 0) throw std::runtime_error("Read timeout");
                    if (res == -1) throw std::system_error(errno, std::system_category(), "select");
                    continue;
                }
                disconnect();
                throw std::system_error(errno, std::system_category(), "recv");
            }
            inbuf_.append(buf, n);
        }
    }

    bool is_connected() const { 
        return connected_; 
    }

    int native() const { 
        return connected_ ? sock_ : -1; 
    }

private:
    std::string       path_;
    int               sock_;
    std::atomic<bool> connected_; // 连接状态标志
    std::string       inbuf_;
};

/* ---------- Client 公有方法 ---------- */
Client::Client(const std::string& path) : pImpl(std::make_unique<Impl>(path)) {}
Client::~Client() = default;
void Client::connect() { pImpl->connect(); }
void Client::disconnect() { pImpl->disconnect(); }
bool Client::is_connected() const { return pImpl->is_connected(); }
void Client::send_line(const std::string& line) { pImpl->send_line(line); }
std::string Client::read_line() { return pImpl->read_line(); }
int Client::native() const { return pImpl->native(); }

} // namespace uds_model
